package com.md.notes.model.module.socket;

import android.os.Environment;
import android.util.Log;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SocketServer {
    private static final String TAG = "SocketServer";
    private static final int PORT = 3000;
    private static final int MAX_CONNECTIONS = 5;
    private static final File baseDir = new File(Environment.getExternalStorageDirectory(), "MdNotes_Temp_Dir");//"/storage/emulated/0/Download/received_files";
    private static final byte PROTOCOL_VERSION = 0x01;
    private static final byte FILE_MARKER = 0x02;
    
    private ServerSocket serverSocket;
    private ExecutorService executorService;
    private boolean isRunning;
    
    public SocketServer() {
        executorService = Executors.newFixedThreadPool(MAX_CONNECTIONS);
        createBaseDir();
    }
    
    private void createBaseDir() {
        // 获取外部存储根目录
        //File baseDir = new File(BASE_DIR);
        if (!baseDir.exists()) {
            if (!baseDir.mkdirs()) {
                Log.e(TAG, "无法创建基础目录");
            }
        }
    }
    
    private boolean isSafePath(String path) {
        try {
            String canonicalBasePath = baseDir.getCanonicalPath();
            String canonicalTargetPath = new File(path).getCanonicalPath();
            return canonicalTargetPath.startsWith(canonicalBasePath);
        } catch (IOException e) {
            Log.e(TAG, "路径安全检查失败", e);
            return false;
        }
    }

    public void start() {
        try {
            serverSocket = new ServerSocket(PORT);
            isRunning = true;
            Log.i(TAG, "文件传输服务器已启动，监听端口: " + PORT);

            while (isRunning) {
                Socket clientSocket = serverSocket.accept();
                executorService.execute(() -> handleClient(clientSocket));
            }
        } catch (IOException e) {
            Log.e(TAG, "服务器启动失败", e);
        }
    }

    public void stop() {
        isRunning = false;
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
            executorService.shutdown();
        } catch (IOException e) {
            Log.e(TAG, "服务器关闭失败", e);
        }
    }

    private void handleClient(Socket clientSocket) {
        String clientAddress = clientSocket.getInetAddress().getHostAddress();
        Log.i(TAG, "[" + clientAddress + "] 新连接建立");

        try (DataInputStream dis = new DataInputStream(clientSocket.getInputStream())) {
            while (true) {
                // 读取协议版本
                byte version = dis.readByte();
                if (version != PROTOCOL_VERSION) {
                    throw new IOException("协议版本错误: " + version);
                }

                // 读取文件夹名
                int nameLen = dis.readUnsignedShort();
                byte[] nameBytes = new byte[nameLen];
                dis.readFully(nameBytes);
                String folderName = new String(nameBytes, StandardCharsets.UTF_8);

                // 读取文件总数
                long fileCount = dis.readLong();
                Log.i(TAG, String.format("[%s] 文件夹: %s, 文件总数: %d", clientAddress, folderName, fileCount));

                // 创建目标文件夹
                String targetDir = baseDir.getAbsolutePath() + File.separator + folderName;
                if (!isSafePath(targetDir)) {
                    throw new IOException("路径越界攻击尝试: " + targetDir);
                }
                new File(targetDir).mkdirs();

                // 处理所有文件
                for (long i = 0; i < fileCount; i++) {
                    receiveFile(dis, targetDir, clientAddress);
                }
            }
        } catch (EOFException e) {
            Log.i(TAG, "[" + clientAddress + "] 客户端断开连接");
        } catch (IOException e) {
            Log.e(TAG, "[" + clientAddress + "] 处理错误", e);
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "关闭socket失败", e);
            }
            Log.i(TAG, "[" + clientAddress + "] 连接关闭");
        }
    }

    private void receiveFile(DataInputStream dis, String targetDir, String clientAddress) throws IOException {
        // 读取文件标识
        byte marker = dis.readByte();
        if (marker != FILE_MARKER) {
            throw new IOException("文件标识错误: " + marker);
        }

        // 读取文件路径
        int pathLen = dis.readUnsignedShort();
        byte[] pathBytes = new byte[pathLen];
        dis.readFully(pathBytes);
        String filePath = new String(pathBytes, StandardCharsets.UTF_8);

        // 读取文件大小
        long fileSize = dis.readLong();
        Log.i(TAG, String.format("[%s] 开始接收文件: %s, 大小: %d字节", clientAddress, filePath, fileSize));

        // 创建完整文件路径
        String fullPath = targetDir + File.separator + filePath;
        if (!isSafePath(fullPath)) {
            throw new IOException("路径越界攻击尝试: " + fullPath);
        }

        // 确保父目录存在
        new File(fullPath).getParentFile().mkdirs();

        // 接收文件数据
        try (FileOutputStream fos = new FileOutputStream(fullPath)) {
            byte[] buffer = new byte[4096];
            long received = 0;
            while (received < fileSize) {
                int toRead = (int) Math.min(buffer.length, fileSize - received);
                int read = dis.read(buffer, 0, toRead);
                if (read == -1) break;
                
                fos.write(buffer, 0, read);
                received += read;
                
                int progress = (int) ((received * 100) / fileSize);
                Log.i(TAG, String.format("[%s] 文件: %s 进度: %d%%", clientAddress, filePath, progress));
            }

            // 验证文件大小
            if (received != fileSize) {
                Log.e(TAG, String.format("[%s] 文件接收不完整: %s, 预期: %d, 实际: %d", 
                    clientAddress, filePath, fileSize, received));
                new File(fullPath).delete();
            } else {
                Log.i(TAG, String.format("[%s] 文件接收完成: %s, 大小: %d字节", 
                    clientAddress, filePath, received));
            }
        }
    }
}
